package cn.maxwell.basic.interceptor;

import ch.qos.logback.classic.turbo.TurboFilter;
import cn.maxwell.basic.annotation.PreAuthorize;
import cn.maxwell.basic.jwt.JwtUtils;
import cn.maxwell.basic.jwt.LoginData;
import cn.maxwell.basic.jwt.Payload;
import cn.maxwell.basic.jwt.RsaUtils;
import cn.maxwell.org.mapper.EmployeeMapper;
import cn.maxwell.user.domain.Logininfo;
import cn.maxwell.user.mapper.LogininfoMapper;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.PublicKey;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 基本步骤：后台拦截器
 * 1.获取token
 * 2.判断token是否为null -- 为null -->拦截 -->跳转到登录页面（token为null说明还没有登录过）
 * 3.通过token获取redis里面的登录信息
 * 4.如果redis为null -->过期了  -->拦截 -->跳转到登录页面
 * 5.redis不为null --> 放行 --> 刷新过期时间（重新保存redis信息）
 */
@Component//把该类交给spring管理
public class LoginInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    LogininfoMapper logininfoMapper;


    @Autowired
    private EmployeeMapper employeeMapper;

    //在请求处理前拦截
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//        //1.获取token
//        String token = request.getHeader("token");
//        //判断token是否为null
//        if(token != null){ //如果token不为空
//            //3.通过token获取redis里面的登录信息
//            Object logininfo = redisTemplate.opsForValue().get(token);//就是获取通过token保存在redislimiande里面的登录信息logininfo
//            if(logininfo != null){
//                //5.redis不为null --> 放行 --> 刷新过期时间（重新保存redis信息）
//                redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES); //刷新过期时间（重新保存redis信息）
//
//                /*权限验证
//                【1.验证是否是前台用户登录（是的话不需要验证受限资源-->放行）
//                 2.如果是后端用户-->验证权限
//                 3.根据logininfo_id获取当前登录人全部权限（连表查询）
//                 4.handler获取当前接口里的sn(preAuthorize注解)
//                 5.包含该权限-->放行
//                 6.不包含该权限-->拦截并向后端传递json信息】
//                 */
//
//                //获取type信息，判断是否是前台用户
//                Logininfo logininfoMsg = (Logininfo) logininfo;
//                if(logininfoMsg.getType()==1){
//                    // 放行
//                    return true;
//                }
//                //这个方法可以获取所有方法名（就是接收请求的接口——方法）
//                HandlerMethod handlerMethod = (HandlerMethod) handler;
//                /*//获取方法名字(用来做测试)
//                String methodName = handlerMethod.getMethod().getName();
//                System.out.println(methodName);*/
//
//                //获取权限自定义注解：preAuthorize
//                PreAuthorize methodAnnotation = handlerMethod.getMethodAnnotation(PreAuthorize.class);
//                //判断是否有preauthorize注解
//                //如果没有的话说明是不受限资源-->放行
//                if(methodAnnotation==null){
//                    return true;
//                }else {
//                    //获取注解里面的sn：权限(当前接口)
//                    String sn = methodAnnotation.sn();
//                    //获取当前登录人员的权限
//                    List<String> sns =  employeeMapper.loadPermissionByLogininfoid(logininfoMsg.getId());
//                    //判断是否包含当前接口的权限-->包含-->放行
//                    if(sns.contains(sn)){
//                        return true;
//                    }
//                        //不包含-->拦截
//                    response.setContentType("application/json;charset=UTF-8");
//                    response.getWriter().println("{\"success\":false,\"message\":\"noPermission\"}");
//                    //拦截
//                    return  false;
//                }
//            }
//        }
//        //2.判断token是否为null -- 为null -->拦截 -->跳转到登录页面（token为null说明还没有登录过）
//        //4.如果redis为null -->过期了  -->拦截 -->跳转到登录页面
//        response.setContentType("application/json;charset=UTF-8");
//        response.getWriter().println("{\"success\":false,\"message\":\"noLogininfo\"}");
//        //拦截
//        return  false;

        //1.获取token
        String token = request.getHeader("token");
        //2.如果有token【jwtToken】执行里面的代码，没有就去登录
        if(token != null) {
            //3.获取公钥
            PublicKey publicKey = RsaUtils.getPublicKey(RsaUtils.class.getClassLoader().getResource("auth_rsa.pub").getFile());
            try {
                //4.将jwtToken解析成想要的数据：LoginData
                Payload<LoginData> payload = JwtUtils.getInfoFromToken(token, publicKey, LoginData.class);
                //刷新过期时间不做 @TODO - 可以用redis保存token串
                if (payload != null) {//登录成功，而且没有过期
                    //5.如获取登录信息对象
                    Logininfo logininfo = payload.getLoginData().getLogininfo();
                    //6.如果是用户 - 放行
                    if (logininfo.getType() == 1) { return true; }
                    //7.如果是后端管理员 - 验证权限【后端管理员 - 角色不一样 - 权限不一样】
                    //8.获取当前接口上注解里的sn - handler - 获取注解@PreAuthorize - 获取注解里面的sn
                    HandlerMethod handlerMethod = (HandlerMethod) handler; //就是接收请求的接口 - 方法
                    //System.out.println(handlerMethod.getMethod().getName());//获取接口名
                    PreAuthorize annotation = handlerMethod.getMethodAnnotation(PreAuthorize.class);
                    if (annotation == null) {//如果当前接口方法上没有这个注解 - 不需要校验权限 - 直接放行
                        return true;
                    } else {
                        String sn = annotation.sn();
                        //9.根据logininfo_id获取当前登录人的所有权限 - sn
                        List<String> sns = logininfoMapper.loadPermissionByLogininfoid(logininfo.getId());
                        if (sns.contains(sn)) {//有权限
                            return true;
                        } else {//else会经过后置拦截器，可以在axios后置拦截器中判断弹出错误框
                            response.setContentType("application/json;charset=UTF-8");
                            response.getWriter().println("{\"success\":false,\"message\":\"noPermission\"}");
                            return false;
                        }
                    }
                }
            } catch(ExpiredJwtException e){
                response.setContentType("application/json;charset=UTF-8");
                response.getWriter().println("{\"success\":false,\"message\":\"timeOut\"}");
                return false;
            }
        }
        //跳转到登录页面 - 后端跳不了，因为后端项目没有页面 - 放在前端跳转
        //告诉浏览器我要给你响应一个json数据，编码集为utf-8
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println("{\"success\":false,\"message\":\"noLogininfo\"}");
        return false;
    }

}
